package dev.xesam.androidkit.utils;

import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
import android.hardware.Camera;
import android.hardware.SensorManager;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Display;
import android.view.WindowManager;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.regex.Pattern;

import static android.hardware.Camera.CameraInfo;

/**
 * 获取设备基本信息
 *
 * @author Wang
 * @data 2015/3/30
 */
public final class DeviceUtil {

    private static final String INVALID_MAC_ADDRESS = "00:00:00:00:00:00";
    private static final Integer MAC_ADDRESS_LENGTH = INVALID_MAC_ADDRESS.length();

    private static Pattern macPattern = Pattern.compile("[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}");

    private static boolean checkMacAddress(String macAddress) {
        if (TextUtils.isEmpty(macAddress) || macAddress.length() != MAC_ADDRESS_LENGTH) {
            return false;
        }
        macAddress = macAddress.toLowerCase();
        if (macPattern.matcher(macAddress).find()) {
            return true;
        }

        return false;
    }

    /**
     * 获取设备的硬件id
     * 获取顺序 IMEI -> UDID
     */
    public static String tryGetHardwareId(Context context) {

        String deviceId = getDeviceId(context);
        if (!TextUtils.isEmpty(deviceId)) {
            return deviceId;
        }

        return UDIDUtil.getUDID(context);
    }

    /**
     * 获取 WLAN mac address
     * 缺点：无wifi设备无法获取
     *
     * @param context
     * @return
     */
    public static String getWlanMacAddress(Context context) {
        WifiManager manager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        WifiInfo info = manager.getConnectionInfo();
        String macAddress = info.getMacAddress();

        if (!checkMacAddress(macAddress)) {
            return null;
        }
        return macAddress;
    }

    /**
     * 获取 Bluetooth mac address
     */
    public static final String getBluetoothMacAddress() {
        String macAddress = null;
        try {
            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
            macAddress = adapter.getAddress();
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (!checkMacAddress(macAddress)) {
            return null;
        }
        return macAddress;
    }

    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    public static final String getSerialId() {
        return Build.SERIAL;
    }

    /**
     * 获取设备id[IMEI等等]
     * IMEI : 15位十进制数字
     * MEID : cdma手机 14位的16进制数字
     * 缺点：非手机无设备id，一些手机设备id不唯一
     *
     * @param context
     * @return
     */
    public static String getDeviceId(Context context) {
        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        return telephonyManager.getDeviceId();
    }

    /**
     * 获取android id
     * 特点：设备boot后重新生成
     * 缺点：2.2版本设备存在bug
     *
     * @param context
     * @return
     */
    public static String getAndroidId(Context context) {
        return Settings.Secure.getString(context.getContentResolver(),
                Settings.Secure.ANDROID_ID);
    }

    @SuppressWarnings("deprecation")
    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    public static String getBuildInfo() {
        StringBuilder sb = new StringBuilder();
        // alpha sort
        sb.append("board: " + Build.BOARD).append("\nbrand: " + Build.BRAND)
                .append("\ncpu_abi: " + Build.CPU_ABI)
                .append("\ncpu_abi2: " + Build.CPU_ABI2)
                .append("\ndevice: " + Build.DEVICE)
                .append("\ndisplay: " + Build.DISPLAY)
                .append("\nfingerprint: " + Build.FINGERPRINT)
                .append("\nhardware: " + Build.HARDWARE)
                .append("\nid: " + Build.ID)
                .append("\nmanufacture: " + Build.MANUFACTURER)
                .append("\nmodel: " + Build.MODEL)
                .append("\nproduct: " + Build.PRODUCT)
                .append("\nradio: " + Build.RADIO)
                .append("\nsdk_int: " + Build.VERSION.SDK_INT);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
            sb.append("\nserial: " + Build.SERIAL);
        }
        sb.append("\ntype: " + Build.TYPE).append("\ntags: " + Build.TAGS);

        return sb.toString();
    }

    public static String getProductInfo() {
        String brand = android.os.Build.BRAND;
        String model = android.os.Build.MODEL;
        String manufacture = android.os.Build.MANUFACTURER;
        String finalInfo = brand + " " + model + "/" + manufacture;
        return finalInfo;
    }


    /////////////////////////////

    public static int getScreenWidth(Context context) {
        return context.getResources().getDisplayMetrics().widthPixels;
    }

    public static final Point getScreenSize(Context context) {
        WindowManager wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();

        DisplayMetrics metrics = new DisplayMetrics();
        display.getMetrics(metrics);
        // since SDK_INT = 1;
        int widthPixels = metrics.widthPixels;
        int heightPixels = metrics.heightPixels;
        // includes window decorations (status bar bar/menu bar)
        if (Build.VERSION.SDK_INT >= 14 && Build.VERSION.SDK_INT < 17) {
            try {
                widthPixels = (Integer) Display.class.getMethod("getRawWidth")
                        .invoke(display);
                heightPixels = (Integer) Display.class
                        .getMethod("getRawHeight").invoke(display);
            } catch (Exception ignored) {
            }
        }
        // includes window decorations (status bar bar/menu bar)
        else if (Build.VERSION.SDK_INT >= 17) {
            try {
                Point realSize = new Point();
                Display.class.getMethod("getRealSize", Point.class).invoke(
                        display, realSize);
                widthPixels = realSize.x;
                heightPixels = realSize.y;
            } catch (Exception ignored) {
            }
        }
        return new Point(widthPixels, heightPixels);
    }

    public static final float getScreenDensity(Context context) {
        Resources resources = context.getResources();
        DisplayMetrics dm = resources.getDisplayMetrics();
        float screenDensity = dm.density;
        return screenDensity;
    }

    public static int getScreenDensityDpi(Context context) {
        Resources resources = context.getResources();
        DisplayMetrics dm = resources.getDisplayMetrics();
        int screenDensityDpi = dm.densityDpi;
        return screenDensityDpi;
    }

    public static double getScreenInches(Context context) {
        double screenInches = -1;
        try {
            Resources resources = context.getResources();
            DisplayMetrics dm = resources.getDisplayMetrics();
            Point point = getScreenSize(context);
            double width = Math.pow(point.x / dm.xdpi, 2);
            double height = Math.pow(point.y / dm.ydpi, 2);
            screenInches = Math.sqrt(width + height);
        } catch (Exception e) {
        }
        return screenInches;
    }

    public static int dp2px(Context context, int dip) {
        Resources resources = context.getResources();
        int px = Math
                .round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                        dip, resources.getDisplayMetrics()));
        return px;
    }

    public static int px2dp(Context context, int px) {
        DisplayMetrics displayMetrics = context.getResources()
                .getDisplayMetrics();
        int dp = Math.round(px
                / (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
        return dp;
    }

    public static int sp2px(Context context, float sp) {
        final float scale = context.getResources().getDisplayMetrics().scaledDensity;
        int px = Math.round(sp * scale);
        return px;
    }

    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    public static final boolean hasFrontCamera() {
        int number = Camera.getNumberOfCameras();
        for (int index = 0; index < number; index++) {
            CameraInfo ci = new CameraInfo();
            Camera.getCameraInfo(index, ci);
            if (ci.facing == CameraInfo.CAMERA_FACING_FRONT) {
                return true;
            }
        }
        return false;
    }

    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    public static final boolean hasBackCamera() {
        int number = Camera.getNumberOfCameras();
        for (int index = 0; index < number; index++) {
            CameraInfo ci = new CameraInfo();
            Camera.getCameraInfo(index, ci);
            if (ci.facing == CameraInfo.CAMERA_FACING_BACK) {
                return true;
            }
        }
        return false;
    }

    public static boolean hasSensor(Context context, int type) {
        SensorManager manager = (SensorManager) context
                .getSystemService(Context.SENSOR_SERVICE);
        return manager.getDefaultSensor(type) != null;
    }

    public static final long getTotalMemory() {
        String memInfoPath = "/proc/meminfo";
        String str2;
        long initial_memory = 0;
        try {
            FileReader fr = new FileReader(memInfoPath);
            BufferedReader bf = new BufferedReader(fr, 8192);
            str2 = bf.readLine();// total memory size
            String[] as = str2.split("\\s+");
            initial_memory = Integer.valueOf(as[1]).intValue() * 1024;
            bf.close();
            return initial_memory;
        } catch (IOException e) {
            return -1;
        }
    }

    public static final boolean screenCap(String localPath) {
        if (FileUtil.exists(localPath)) {
            FileUtil.delete(localPath);
        }

        if (!FileUtil.create(localPath)) {
            return false;
        }

        ShellUtil shell = new ShellUtil();
        // failed to run 'su' command
        if (shell.prepare(true)) {
            return false;
        }
        String command = "screencap -p '" + localPath + ",";
        ShellResult result = shell.execute(command);
        return (result != null && result.success());
    }

}
